package com.ruoyi.system.controller;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.system.domain.LogEntry;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@RestController
@RequestMapping("/sys/logc")
public class LogcController extends BaseController {

    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static final Pattern logPattern = Pattern.compile("Recv from\\s+\"IF_Rsu_ToLogic\"\\s+:\\s*\\{([^}]*)\\}|" + "Send to\\s+\"IF_RsuLogic_Ctrl\"\\s+:\\s*\\{([^}]*)\\}");
    private static final Pattern obuIdPattern = Pattern.compile("TnlDebugData:.*?OBUPlate=([^,]*),.*?ObuId=(\\w+).*?OpTime=.*?");
    private static final Pattern frameDataPattern = Pattern.compile("FrameData:\\s*FF(\\d)8B3([0-9A-Fa-f]+)");

    // 用于存储上次读取位置的Map
    private static final Map<String, Long> lastReadPositions = new ConcurrentHashMap<>();

    // 存储 <ObuId, FrameData> 对的映射表
    private static final Map<String, String> obuIdToFrameData = new ConcurrentHashMap<>();
    private static final Map<String, String> obuIdToPlate = new ConcurrentHashMap<>();

    @GetMapping("/loads")
    public List<LogEntry> parseLogFile(HttpServletRequest request) throws IOException {
        String dirPath = request.getParameter("dirPath");
        String rsuCtrlPath = request.getParameter("rsuCtrlPath");
        String rsuLogcPath = request.getParameter("rsuLogcPath");

        // Step 1: Collect ObuIds and their corresponding FrameData from a.log
        collectObuIds(dirPath, rsuCtrlPath);

        // Step 2: Parse b.log with collected ObuIds
        List<LogEntry> entries = parseLogsWithObuIds(dirPath, rsuLogcPath);

        Set<LogEntry> uniqueEntriesSet = new HashSet<>(entries);
        List<LogEntry> uniqueEntries = new ArrayList<>(uniqueEntriesSet);

        return uniqueEntries;
    }

    private void collectObuIds(String dirPath, String rsuCtrlPath) throws IOException {
        Path aLogFilePath = Paths.get(dirPath, rsuCtrlPath);
        if (Files.exists(aLogFilePath)) {
            try (RandomAccessFile reader = new RandomAccessFile(aLogFilePath.toFile(), "r")) {
                long lastPosition = lastReadPositions.getOrDefault(aLogFilePath.toString(), 0L);
                reader.seek(lastPosition);

                StringBuilder logBuilder = new StringBuilder();
//                String line;
                String obuId = null;
                String obuPlate = null;
                String ef01 = null;

                byte[] buffer = new byte[1024];
                int bytesRead;
                StringBuilder contentBuilder = new StringBuilder();

                // Read bytes and decode using GB2312
                while ((bytesRead = reader.read(buffer)) != -1) {
                    contentBuilder.append(new String(buffer, 0, bytesRead, Charset.forName("GB2312")));
                }

                // Process the entire content as one string
                String content = contentBuilder.toString();
                String[] lines = content.split(System.lineSeparator());

//                while ((line = reader.readLine()) != null) {
                    for (String line : lines) {
                    Matcher aLogMatcher = obuIdPattern.matcher(line);
                    if (aLogMatcher.find()) {
                        obuPlate = aLogMatcher.group(1);
                        obuId = aLogMatcher.group(2);
                        obuIdToPlate.put(obuId, obuPlate);
                    }

                    // 尝试在每行中匹配 FrameData
                    Matcher frameDataMatcher = frameDataPattern.matcher(line);
                    if (frameDataMatcher.find() && obuPlate != null && obuId != null) {
                        // 提取 FrameData 并进行处理
                        String hexData = frameDataMatcher.group(2);
                        if (hexData.length() >= 20) {
                            ef01 = hexData.substring(10, hexData.length() - 4);
                            // 存储 ObuId 和 FrameData 的对应关系
                            obuIdToFrameData.put(obuId, ef01);
                        }
                    }

                    // 更新最后读取的位置
                    lastReadPositions.put(aLogFilePath.toString(), reader.getFilePointer());
                }
            }
        }
    }

    private List<LogEntry> parseLogsWithObuIds(String dirPath, String rsuLogcPath) throws IOException {
        List<LogEntry> entries = new ArrayList<>();
        Path bLogFilePath = Paths.get(dirPath, rsuLogcPath);
        if (Files.exists(bLogFilePath)) {
            for (String obuId : obuIdToFrameData.keySet()) {
                String ef01 = obuIdToFrameData.get(obuId);
                String plate = obuIdToPlate.get(obuId);
                entries.addAll(parseLogcWithObuId(bLogFilePath.toString(), obuId, ef01, plate));
            }
        }
        return entries;
    }

//    private List<LogEntry> parseLogcWithObuId(String filePath, String obuId, String ef01, String plate) throws IOException {
//        List<LogEntry> entries = new ArrayList<>();
//        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
//            StringBuilder logBuilder = new StringBuilder();
//            boolean inMultilineLog = false;
//
//            String line;
//            while ((line = reader.readLine()) != null) {
//                if (!inMultilineLog && (line.contains("Recv from  \"IF_Rsu_ToLogic\" : {") || line.contains("Send to  \"IF_RsuLogic_Ctrl\" : {"))) {
//                    inMultilineLog = true;
//                    logBuilder.append(line.trim());
//                } else if (inMultilineLog) {
//                    logBuilder.append(line.trim());
//                    if (line.trim().endsWith("}")) {
//                        inMultilineLog = false;
//                        processLogEntry(logBuilder.toString(), entries, obuId, ef01, plate);
//                        logBuilder.setLength(0);
//                    }
//                }
//            }
//        }
//        return entries;
//    }

    private List<LogEntry> parseLogcWithObuId(String filePath, String obuId, String ef01, String plate) throws IOException {
        List<LogEntry> entries = new ArrayList<>();
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(new FileInputStream(filePath), Charset.forName("GB2312")))) {
            StringBuilder logBuilder = new StringBuilder();
            boolean inMultilineLog = false;

            String line;
            while ((line = reader.readLine()) != null) {
                if (!inMultilineLog && (line.contains("Recv from  \"IF_Rsu_ToLogic\" : {") || line.contains("Send to  \"IF_RsuLogic_Ctrl\" : {"))) {
                    inMultilineLog = true;
                    logBuilder.append(line.trim());
                } else if (inMultilineLog) {
                    logBuilder.append(line.trim());
                    if (line.trim().endsWith("}")) {
                        inMultilineLog = false;
                        processLogEntry(logBuilder.toString(), entries, obuId, ef01, plate);
                        logBuilder.setLength(0);
                    }
                }
            }
        }
        return entries;
    }

    private void processLogEntry(String logEntry, List<LogEntry> entries, String obuId, String ef01, String plate) {
        Matcher matcher = logPattern.matcher(logEntry);
        if (matcher.find()) {
            String jsonPart = matcher.group().replaceAll("Recv from\\s+\"IF_Rsu_ToLogic\"\\s+:\\s*|Send to\\s+\"IF_RsuLogic_Ctrl\"\\s+:\\s*", "").trim();

            if (jsonPart.isEmpty() || !jsonPart.startsWith("{") || !jsonPart.endsWith("}")) {
                System.err.println("Invalid JSON part: " + jsonPart);
                return;
            }

            try {
                JsonNode rootNode = objectMapper.readTree(jsonPart);
                if ("B4".equals(rootNode.path("FrameType").asText())) {
                    String entryObuId = rootNode.path("ObuId").asText();
                    if (entryObuId.equals(obuId)) {
                        LogEntry entry = new LogEntry();
                        entry.setObuPlate(plate);
                        entry.setObuId(obuId);
                        entry.setIcCard0002(rootNode.path("ICCardFile0002").asText());
                        entry.setIcCard0015(rootNode.path("ICCardFile0015").asText());
                        entry.setIcCard0019(rootNode.path("ICCardFile0019").asText());
                        entry.setEf04Info(rootNode.path("B4EF04Info").asText());
                        entry.setEf01Info(ef01);

                        entries.add(entry);
                    }
                }
            } catch (IOException e) {
                System.err.println("Error parsing JSON: " + e.getMessage());
                System.err.println("Failed JSON part: " + jsonPart);
            }
        }
    }
}